/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */

#include "ActiveMultithreaded.h"
#include <math/utl.h>
#include "Manager.h"
#include <threads/Lock.h>
#include <logs/Log.h>
#include <Gluck.h>
#include <threads/Thread.h>
#include <threads/threads.h>
#include <list>

namespace liba
{
namespace resource
{

#if defined(ANDROID_NDK) || defined(SAMSUNG_VERSION)
#define IPHONE_VERSION
#endif

#ifndef IPHONE_VERSION
class ActiveMultithreadedLoader: private threads::Thread
{
protected:
	virtual void run()
	{
		while( !need_termination() )
		{
			{
				threads::Lock lock( list_mutex );
				if( resources.size() )
				{
					cur = resources.front();
					resources.pop_front();
				}
			}
			threads::Lock lock( cur_mutex );
			if( cur )
			{
				//this is strange
//				threads::sleep( 10 ); // TODO - decrease sleep time
				cur->internal_load();
				cur = 0;
			}
			else
				threads::sleep( 100 );
		}
	}
	
	void internal_add( ActiveMultithreaded * res )
	{
		threads::Lock lock( list_mutex );
		resources.push_back( res );
	}
	
	void internal_remove( ActiveMultithreaded * res )
	{
		threads::Lock lock( list_mutex );
		if( cur == res )
		{
			threads::Lock lock( cur_mutex );
			cur = 0;
			return;
		}
		resources.remove( res );
	}
public:
	ActiveMultithreadedLoader()
	:	 cur( 0 )
	{
		start();
	}
	~ActiveMultithreadedLoader()
	{
		request_termination();
		wait_termination();
	}

	static void add_resource( ActiveMultithreaded * res )
	{
		loader->internal_add( res );
	}
	
	static void remove_resource( ActiveMultithreaded * res )
	{
		loader->internal_remove( res );
	}
	static ActiveMultithreadedLoader * loader;
private:
	typedef std::list<ActiveMultithreaded*> ResList;
	ResList resources;
	threads::Mutex list_mutex;
	threads::Mutex cur_mutex;
	ActiveMultithreaded * cur;

	friend class ActiveMultithreaded;
};
#else
	class ActiveMultithreadedLoader
		{
		public:
			void LifeCycle()
			{
				int counter = 0;
				while( resources.size() )
				{
					cur = resources.front();
					resources.pop_front();
					
					if( cur )
					{
						cur->internal_load();
						cur = 0;
						
						//TODO: better to use timer
						++counter;
						if(counter > 10)
							return;
					}
				}
			}
			
			void internal_add( ActiveMultithreaded * res )
			{
				resources.push_back( res );
			}
			
			void internal_remove( ActiveMultithreaded * res )
			{
				resources.remove( res );
			}
		public:
			ActiveMultithreadedLoader()
			:	 cur( 0 )
			{}
			~ActiveMultithreadedLoader()
			{}
			
			static void add_resource( ActiveMultithreaded * res )
			{
				loader->internal_add( res );
			}
			
			static void remove_resource( ActiveMultithreaded * res )
			{
				loader->internal_remove( res );
			}
			static ActiveMultithreadedLoader * loader;
		private:
			typedef std::list<ActiveMultithreaded*> ResList;
			ResList resources;
			ActiveMultithreaded * cur;
			
			friend class ActiveMultithreaded;
		};
#endif

ActiveMultithreadedLoader * ActiveMultithreadedLoader::loader = 0;

	void ActiveMultithreaded::Creator::LifeCycle()
	{
#ifdef IPHONE_VERSION
		if(ActiveMultithreadedLoader::loader)
			ActiveMultithreadedLoader::loader->LifeCycle();
#endif
	}
	
ActiveMultithreaded::Creator::Creator()
{
	if( ActiveMultithreadedLoader::loader )
		THROW(Gluck(__FUNCTION__, "ActiveMultithreadedLoader::loader already exist"));
	ActiveMultithreadedLoader::loader = new ActiveMultithreadedLoader();
}

ActiveMultithreaded::Creator::~Creator()
{
	delete ActiveMultithreadedLoader::loader; ActiveMultithreadedLoader::loader = 0;
}

ActiveMultithreaded::ActiveMultithreaded(const filesystem::String & name)
:	name( name ),
	res( 0 ),
	pos( 0 ),
	ready( false ),
	valid( true )
{
	ActiveMultithreadedLoader::add_resource( this );
//	internal_load();
}

ActiveMultithreaded::~ActiveMultithreaded()
{
	if( !ready )
		ActiveMultithreadedLoader::remove_resource( this  );
	delete res; res = 0;
}

int ActiveMultithreaded::read(void * data, int count)
{
	int real_count = math::min( count, static_cast<int>( acquired_data.size() ) - pos );
	memmove( data, &(acquired_data.front()) + pos, real_count );
	pos += real_count;
	return real_count;
}

int ActiveMultithreaded::skip(int count)
{
	int real_count = math::min( count, static_cast<int>( acquired_data.size() ) - pos );
	pos += real_count;
	return real_count;
}

bool ActiveMultithreaded::is_valid()const
{
	return valid;
}

int ActiveMultithreaded::get_size()const
{
	return static_cast<int>( acquired_data.size() );
}

int ActiveMultithreaded::get_position()const
{
	return pos;
}

void ActiveMultithreaded::reset(int position)
{
	pos = position;
}

const void * ActiveMultithreaded::get_data()const
{
	return &(acquired_data.front());
}

bool ActiveMultithreaded::is_ready()volatile const
{
	return ready;
}

void ActiveMultithreaded::internal_load()
{
	res = Manager::create_resource( name );	
	if( !res )
	{
///		logs::log() << logs::error << "In ActiveMultithreaded::internal_load() create_resource failed\n";
		valid = false;
		ready = true;
		return;
	}
///	logs::log() << "ActiveMultithreaded::internal_load() " << name << "\n";
///	logs::log() << logs::error << "In ActiveMultithreaded::internal_load() create_resource succeded\n";
	acquired_data.resize( res->get_size() );
	if( res->read( &(acquired_data.front()), acquired_data.size() ) != acquired_data.size() )
		valid = false;
	delete res; res = 0;
	ready = true;
}

} // namespace resource
} // namespace liba


